package com.kexuexiong.demo.bear.common.multiDataSource;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.kexuexiong.demo.bear.entity.ComDataSource;
import com.kexuexiong.demo.bear.service.ComDatasourceService;
import io.seata.rm.datasource.DataSourceProxy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.AbstractDataSource;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

@Slf4j
@Component("dynamicDataSource")
public class DynamicDataSource extends AbstractDataSource implements DataSourceManager, InitializingBean {

    @Autowired
    private ComDatasourceService datasourceService;

    private Map<String, DataSource> DATA_SOURCE_MAP = new HashMap<>();

    private Environment environment;

    @Autowired
    public DynamicDataSource(Environment environment){
        this.environment = environment;
    }


    private static DruidDataSource DEFAULT_DATA_SOURCE;

    @Value("${spring.datasource.url}")
    private String baseUrl = "jdbc:mysql://localhost:3306/demo?tinyInt1isBit=false&nullCatalogMeansCurrent=true&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8";

    @Value("${spring.datasource.username}")
    private String baseUserName = "root";

    @Value("${spring.datasource.password}")
    private String basePassword = "root";


    @Override
    public void put(String dataSourceName, DataSource dataSource) {

    }

    @Override
    public DataSource get(String dataSourceName) {
        return DATA_SOURCE_MAP.get(dataSourceName);
    }

    @Override
    public Boolean hasDataSource(String dataSourceName) {
        return DATA_SOURCE_MAP.containsKey(dataSourceName);
    }

    @Override
    public void remove(String dataSourceName) {
        DATA_SOURCE_MAP.remove(dataSourceName);
    }

    @Override
    public void closeDataSource(String dataSourceName) {
        DataSource dataSource = DATA_SOURCE_MAP.get(dataSourceName);
        if (Objects.nonNull(dataSource)) {
            if (dataSource instanceof DruidDataSource) {
                DruidDataSource druidDataSource = (DruidDataSource) dataSource;
                druidDataSource.close();
            }
        }
    }

    @Override
    public Collection<DataSource> all() {
        return this.DATA_SOURCE_MAP.values();
    }

    @Override
    public Connection getConnection() throws SQLException {
        log.info("dataSourceContext:{}", DataSourceContextHolder.getDataSourceContext());
        DataSource dataSource = Optional.ofNullable(DataSourceContextHolder.getDataSourceContext())
                .map(DATA_SOURCE_MAP::get)
                .orElse(DEFAULT_DATA_SOURCE);
        if (Objects.isNull(dataSource)) {
            DEFAULT_DATA_SOURCE = new DruidDataSource();
            DEFAULT_DATA_SOURCE.setUsePingMethod(true);
            DEFAULT_DATA_SOURCE.setUrl(environment.getProperty("spring.datasource.url"));
            DEFAULT_DATA_SOURCE.setUsername(environment.getProperty("spring.datasource.username"));
            DEFAULT_DATA_SOURCE.setPassword(environment.getProperty("spring.datasource.password"));
            DEFAULT_DATA_SOURCE.setFilters(environment.getProperty("spring.datasource.druid.filters"));
            DEFAULT_DATA_SOURCE.setMaxActive(20);
            DEFAULT_DATA_SOURCE.setInitialSize(1);
            DEFAULT_DATA_SOURCE.setMaxWait(6000);
            DEFAULT_DATA_SOURCE.setName("default");
            DEFAULT_DATA_SOURCE.setMinIdle(20);
            DEFAULT_DATA_SOURCE.setPoolPreparedStatements(true);
            dataSource = new DataSourceProxy(DEFAULT_DATA_SOURCE);
        }
        return dataSource.getConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        log.info("dataSourceContext:{}", DataSourceContextHolder.getDataSourceContext());
        DataSource dataSource = Optional.ofNullable(DataSourceContextHolder.getDataSourceContext())
                .map(DATA_SOURCE_MAP::get)
                .orElse(DEFAULT_DATA_SOURCE);
        if (Objects.isNull(dataSource)) {
            throw new RuntimeException("数据源不存在！");
        }
        return dataSource.getConnection(username, password);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("初始化数据源...");
        List<ComDataSource> dataSourceList = datasourceService.lambdaQuery().eq(ComDataSource::getStatus, 1).list();
        if (CollectionUtil.isNotEmpty(dataSourceList)) {
            for (ComDataSource comDataSource : dataSourceList) {
                DruidDataSource druidDataSource = new DruidDataSource();
                druidDataSource.setUsePingMethod(true);
                druidDataSource.setUrl(comDataSource.getJdbcUrl());
                druidDataSource.setUsername(comDataSource.getUserName());
                druidDataSource.setPassword(comDataSource.getPassword());
                druidDataSource.setFilters("stat,wall");
                druidDataSource.setMaxActive(comDataSource.getMaxPoolSize());
                druidDataSource.setInitialSize(1);
                druidDataSource.setMaxWait(60000);
                druidDataSource.setName(comDataSource.getName());
                druidDataSource.setMinIdle(comDataSource.getMinIdel());
                druidDataSource.setPoolPreparedStatements(true);
                log.info("初始化数据源NAME：{}", comDataSource.getName());
                DATA_SOURCE_MAP.put(comDataSource.getName(),new DataSourceProxy(druidDataSource));
            }
        }
        log.info("初始化数据源结束，DATA_SOURCE_MAP：{}", DATA_SOURCE_MAP.size());
    }
}
